home *** CD-ROM | disk | FTP | other *** search
/ FishMarket 1.0 / FishMarket v1.0.iso / fishies / 126-150 / disk_128 / wkeys / bindwkeys.c < prev    next >
C/C++ Source or Header  |  1992-05-06  |  23KB  |  855 lines

  1. /*
  2.  *  BindWKeys.c     Reads a file and creates an array of key bindings
  3.  *                  to be used by a hot-key handler to tell which keys
  4.  *                  do what.
  5.  *
  6.  *             Copyright (c) 1987 by Davide P. Cervone
  7.  *  You may use this code provided this copyright notice is left intact.
  8.  */
  9.  
  10. #include <exec/types.h>
  11. #include <exec/memory.h>
  12. #include <devices/inputevent.h>
  13. #ifndef NO_FILE
  14. #include <stdio.h>
  15. #endif
  16.  
  17. #include "wKeys.h"
  18.  
  19. #ifndef NO_FILE
  20. #define KEYMASK         0x00FF      /* default qualifier key mask */
  21. #define SHIFT           IECODE_UP_PREFIX
  22.  
  23. #define BADVALUE        -1          /* error while parsing input line */
  24.  
  25. /*
  26.  *  Macros to tell whether a character is printable or not, and
  27.  *  whether it is not alphanumeric
  28.  */
  29. #define PRINTABLE(c)    ((c)>=' '&&(c)<='~')
  30. #define NOTPRINTABLE(c) ((c)<' '||(c)>'~')
  31. #define NOTALPHANUM(c)\
  32.    ((c)<'0'||((c)>'9'&&(c)<'A')||((c)>'Z'&&(c)<'a')||(c)>'z')
  33.  
  34. /*
  35.  *  Create a new instance of a given structure type
  36.  */
  37. #define NEW(s,var)      (var = (struct s *)New("var",sizeof(struct s)))
  38.  
  39.  
  40. #define LINESIZE    132
  41. static char InputLine[LINESIZE+1];    /* the line read from the file */
  42. static char *CurPos;                  /* current character position in line */
  43. static char *CurWord;                 /* pointer to begining of current word */
  44. static char TerminationChar;          /* character that ended the word */
  45. static int LineCount = 0;             /* number of lines read from the file */
  46. #endif
  47.  
  48. struct HotKeyItem *KeyList = NULL;    /* the list of key definitions so far */
  49. struct HotKey *KeyArray = NULL;       /* the sorted array of key definitions */
  50. int KeyCount = 0;                     /* the number of key definitions */
  51. #define KEYARRAYSIZE    (KeyCount*sizeof(struct HotKey))
  52.  
  53. #ifndef NO_FILE
  54. static FILE *InFile = NULL;           /* the input file */
  55. #define ERROR _OSERR                  /* the system's error variable */
  56. extern int ERROR;
  57.  
  58.  
  59. /*
  60.  *  This structure maps a character string to a numeric value.  It is used
  61.  *  for mapping key names to keyboard scan codes and key action names to 
  62.  *  action numbers.
  63.  */
  64.  
  65. struct Definition
  66. {
  67.    char *Name;
  68.    UBYTE Code;
  69. };
  70.  
  71.  
  72. /*
  73.  *  Qualifier[] maps the names of the qualifier keys to their corresponding 
  74.  *  bit positions within the ie_Qualifier field of an InputEvent.  This List 
  75.  *  is sorted by name.  Note that LCOMMAND is equivalent to LAMIGA, etc.  
  76.  *  Note also that there are some compound qualifier names, such as SHIFT.  
  77.  *  These are expanded into more than one key definition.
  78.  *
  79.  *  See devices/inputevent.h for more details on qualifier values.
  80.  */
  81.  
  82. static struct Definition Qualifier[] =
  83. {
  84.    {"ALT",20},
  85.    {"AMIGA",22},
  86.    {"CAPSLOCK",2},
  87.    {"CONTROL",3},
  88.    {"INTERRUPT",10},
  89.    {"KEYUP",31},
  90.    {"LALT",4},
  91.    {"LAMIGA",6},
  92.    {"LBUTTON",14},
  93.    {"LCOMMAND",6},
  94.    {"LSHIFT",0},
  95.    {"MBUTTON",12},
  96.    {"MULTIBROADCAST",11},
  97.    {"NUMERICPAD",8},
  98.    {"RALT",5},
  99.    {"RAMIGA",7},
  100.    {"RBUTTON",13},
  101.    {"RCOMMAND",7},
  102.    {"RELATIVEMOUSE",15},
  103.    {"REPEAT",9},
  104.    {"RSHIFT",1},
  105.    {"SHIFT",16},
  106. };
  107. #define MAXQUALIFIER    (sizeof(Qualifier)/sizeof(struct Definition))
  108.  
  109.  
  110. /*
  111.  *  AsciiToKeyCode[] maps ASCII characters to keyboard scan-codes.  This array 
  112.  *  is in ASCII order.  SHIFT indicates that one of the shift keys must be 
  113.  *  held down together with the correct key in order to produce that ASCII 
  114.  *  character.  Note, however, that upper- and lower-case letters both are 
  115.  *  mapped to un-shifted keys.
  116.  */
  117.  
  118. static UBYTE AsciiToKeyCode[] =
  119. {
  120.    0x01 | SHIFT,    /* ! */
  121.    0x2A | SHIFT,    /* " */
  122.    0x03 | SHIFT,    /* # */
  123.    0x04 | SHIFT,    /* $ */
  124.    0x05 | SHIFT,    /* % */
  125.    0x07 | SHIFT,    /* & */
  126.    0x2A,            /* ' */
  127.    0x09 | SHIFT,    /* ( */
  128.    0x0A | SHIFT,    /* ) */
  129.    0x08 | SHIFT,    /* * */
  130.    0x0C | SHIFT,    /* + */
  131.    0x38,            /* , */
  132.    0x0B,            /* - */
  133.    0x39,            /* . */
  134.    0x3A,            /* / */
  135.    0x0A,            /* 0 */
  136.    0x01,            /* 1 */
  137.    0x02,            /* 2 */
  138.    0x03,            /* 3 */
  139.    0x04,            /* 4 */
  140.    0x05,            /* 5 */
  141.    0x06,            /* 6 */
  142.    0x07,            /* 7 */
  143.    0x08,            /* 8 */
  144.    0x09,            /* 9 */
  145.    0x29 | SHIFT,    /* : */
  146.    0x29,            /* ; */
  147.    0x38 | SHIFT,    /* < */
  148.    0x0C,            /* = */
  149.    0x39 | SHIFT,    /* > */
  150.    0x3A | SHIFT,    /* ? */
  151.    0x02 | SHIFT,    /* @ */
  152.    0x20,            /* A */
  153.    0x35,            /* B */
  154.    0x33,            /* C */
  155.    0x22,            /* D */
  156.    0x12,            /* E */
  157.    0x23,            /* F */
  158.    0x24,            /* G */
  159.    0x25,            /* H */
  160.    0x17,            /* I */
  161.    0x26,            /* J */
  162.    0x27,            /* K */
  163.    0x28,            /* L */
  164.    0x37,            /* M */
  165.    0x36,            /* N */
  166.    0x18,            /* O */
  167.    0x19,            /* P */
  168.    0x10,            /* Q */
  169.    0x13,            /* R */
  170.    0x21,            /* S */
  171.    0x14,            /* T */
  172.    0x16,            /* U */
  173.    0x34,            /* V */
  174.    0x11,            /* W */
  175.    0x32,            /* X */
  176.    0x15,            /* Y */
  177.    0x31,            /* Z */
  178.    0x1A,            /* [ */
  179.    0x0D | SHIFT,    /* \ */
  180.    0x1B,            /* ] */
  181.    0x06 | SHIFT,    /* ^ */
  182.    0x0B | SHIFT,    /* _ */
  183.    0x00,            /* ` */
  184.    0x20,            /* a */
  185.    0x35,            /* b */
  186.    0x33,            /* c */
  187.    0x22,            /* d */
  188.    0x12,            /* e */
  189.    0x23,            /* f */
  190.    0x24,            /* g */
  191.    0x25,            /* h */
  192.    0x17,            /* i */
  193.    0x26,            /* j */
  194.    0x27,            /* k */
  195.    0x28,            /* l */
  196.    0x37,            /* m */
  197.    0x36,            /* n */
  198.    0x18,            /* o */
  199.    0x19,            /* p */
  200.    0x10,            /* q */
  201.    0x13,            /* r */
  202.    0x21,            /* s */
  203.    0x14,            /* t */
  204.    0x16,            /* u */
  205.    0x34,            /* v */
  206.    0x11,            /* w */
  207.    0x32,            /* x */
  208.    0x15,            /* y */
  209.    0x31,            /* z */
  210.    0x1A | SHIFT,    /* { */
  211.    0x0D | SHIFT,    /* | */
  212.    0x1B | SHIFT,    /* } */
  213.    0x00 | SHIFT,    /* ~ */
  214. };
  215. #define MAXASCII    sizeof(AsciiToKeyCode)
  216.  
  217.  
  218. /*
  219.  *  Key[] maps key names to their keyboard scan-codes.  This array is sorted
  220.  *  by name.  SHIFT means that a SHIFT key must be held down in addition to
  221.  *  the indicated key.  Some keys have more than one name (e.g., ESCAPE is
  222.  *  equivalent to ESC).  Note that pressing a qualifier key also can be
  223.  *  detected.
  224.  */
  225.  
  226. static struct Definition Key[] =
  227. {
  228.    {"BACKSPACE",0x41},
  229.    {"BS", 0x41},
  230.    {"CAPSLOCKKEY",0x62},
  231.    {"COLON",0x29 | SHIFT},
  232.    {"COMMA",0x38},
  233.    {"CONTROLKEY",0x63},
  234.    {"DASH",0x0B},
  235.    {"DEL",0x46},
  236.    {"DELETE",0x46},
  237.    {"DOT",0x3C},
  238.    {"DOWNARROW",0x4D},
  239.    {"ENTER",0x42},
  240.    {"ESC",0x45},
  241.    {"ESCAPE",0x45},
  242.    {"F1",0x50},
  243.    {"F10",0x59},
  244.    {"F2",0x51},
  245.    {"F3",0x52},
  246.    {"F4",0x53},
  247.    {"F5",0x54},
  248.    {"F6",0x55},
  249.    {"F7",0x56},
  250.    {"F8",0x57},
  251.    {"F9",0x58},
  252.    {"HELP",0x5F},
  253.    {"KP0",0x0F},
  254.    {"KP1",0x1D},
  255.    {"KP2",0x1E},
  256.    {"KP3",0x1F},
  257.    {"KP4",0x2D},
  258.    {"KP5",0x2E},
  259.    {"KP6",0x2F},
  260.    {"KP7",0x3D},
  261.    {"KP8",0x3E},
  262.    {"KP9",0x3F},
  263.    {"LALTKEY",0x64},
  264.    {"LAMIGAKEY",0x66},
  265.    {"LCOMMANDKEY",0x66},
  266.    {"LEFTARROW",0x4F},
  267.    {"LSHIFTKEY",0x60},
  268.    {"MINUS",0x4A},
  269.    {"RALTKEY",0x65},
  270.    {"RAMIGAKEY",0x67},
  271.    {"RCOMMANDKEY",0x67},
  272.    {"RETURN",0x44},
  273.    {"RIGHTARROW",0x4E},
  274.    {"RSHIFTKEY",0x61},
  275.    {"SPACE",0x40},
  276.    {"TAB",0x42},
  277.    {"UPARROW",0x4C},
  278. };
  279. #define MAXKEY      (sizeof(Key)/sizeof(struct Definition)) 
  280.  
  281.  
  282. /*
  283.  *  Action[] maps key action names to their action numbers (used by the
  284.  *  input handler to perform the action when the key is pressed).  This array
  285.  *  is sorted by name.
  286.  */
  287.  
  288. static struct Definition Action[] =
  289. {
  290.    {"BACK-WINDOW-TO-FRONT", BACKTOFRONT},
  291.    {"FRONT-WINDOW-TO-BACK", FRONTTOBACK},
  292.    {"NEXT-WINDOW",          ACTIVATENEXT},
  293.    {"PREVIOUS-WINDOW",      ACTIVATEPREVIOUS},
  294.    {"SCREEN-TO-BACK",       SCREENTOBACK},
  295.    {"SCREEN-TO-FRONT",      SCREENTOFRONT},
  296.    {"WINDOW-TO-BACK",       WINDOWTOBACK},
  297.    {"WINDOW-TO-FRONT",      WINDOWTOFRONT},
  298. };
  299. #define MAXACTION   (sizeof(Action)/sizeof(struct Definition))
  300. #endif
  301.  
  302. /*
  303.  *  Some shorthand macros used to define the default key layout
  304.  */
  305.  
  306. #define RAMIGA      IEQUALIFIER_RCOMMAND
  307. #define RSHIFT      IEQUALIFIER_RSHIFT
  308.  
  309. #define UPARROW     0x4C
  310. #define DOWNARROW   0x4D
  311. #define RIGHTARROW  0x4E
  312. #define LEFTARROW   0x4F
  313.  
  314. #define HOTKEY(q,c,a)  {{c,0,q},{0xFF,a,RAMIGA|RSHIFT}}
  315.  
  316.  
  317. /*
  318.  *  DefaultKey[] maps the default key layout.  This array is sorted by
  319.  *  KeyCode value.  Change this array to change the default key bindings.
  320.  */
  321.  
  322. static struct HotKey DefaultKey[] =
  323. {
  324.    HOTKEY(          RAMIGA, UPARROW,    WINDOWTOFRONT),
  325.    HOTKEY( RSHIFT | RAMIGA, UPARROW,    SCREENTOFRONT),
  326.    HOTKEY(          RAMIGA, DOWNARROW,  WINDOWTOBACK),
  327.    HOTKEY( RSHIFT | RAMIGA, DOWNARROW,  SCREENTOBACK),
  328.    HOTKEY(          RAMIGA, RIGHTARROW, ACTIVATENEXT),
  329.    HOTKEY( RSHIFT | RAMIGA, RIGHTARROW, FRONTTOBACK),
  330.    HOTKEY(          RAMIGA, LEFTARROW,  ACTIVATEPREVIOUS),
  331.    HOTKEY( RSHIFT | RAMIGA, LEFTARROW,  BACKTOFRONT),
  332. };
  333. #define DEFAULTSIZE (sizeof(DefaultKey)/sizeof(struct HotKey))
  334.  
  335.  
  336. #ifndef NO_FILE
  337. /*
  338.  *  Error()
  339.  *
  340.  *  Print an error message and the line number where the error occured.
  341.  *  Return the error value.
  342.  */
  343.  
  344. static int Error(s,x1,x2,x3)
  345. char *s, *x1,*x2,*x3;
  346. {
  347.    printf("Line %2d:  ",LineCount);
  348.    printf(s,x1,x2,x3);
  349.    printf("\n");
  350.    return(BADVALUE);
  351. }
  352.  
  353.  
  354. /*
  355.  *  GetNextWord()
  356.  *
  357.  *  Isolate the next word in the line read from the file.
  358.  *  If we are not at the end of the line, then
  359.  *    skip over leading spaces,
  360.  *    set CurWord to point to the beginning of the word,
  361.  *    while we are not at the end of the word,
  362.  *      check if the current character is a word delimiter:
  363.  *      if it is a space or a tab,
  364.  *        skip additional spaces or tabs,
  365.  *        set the terminator character,
  366.  *        and end the word.  
  367.  *        (At this point, CurPos will be pointing to the "real" delimiter,
  368.  *        or to the beginning of the next word, if the delimiter really was
  369.  *        a space).
  370.  *      if it was a NULL, convert it to a new-line.
  371.  *      if it was a dash, comma, colon or new-line,
  372.  *        save the termination character for later,
  373.  *        replace the charactger with a NULL so that CurWord will end at
  374.  *          the end of the word,
  375.  *        and stop looking for more of the word.
  376.  *      otherwise
  377.  *       if we're still looking for the end of the word (i.e., we have not
  378.  *         ended, it by hitting a space),
  379.  *         if its unprintable or the current word is more than one character
  380.  *           long and the current character is not alphanumeric,
  381.  *           then record the bad character and end the word
  382.  *         go on to the next character (i.e., add the current one to the word)
  383.  */
  384.  
  385. static void GetNextWord()
  386. {
  387.    short NotDone = TRUE;
  388.    char c;
  389.  
  390.    if (TerminationChar != '\n')
  391.    {
  392.       while (*CurPos == ' ' || *CurPos == '\t') CurPos++;
  393.       CurWord = CurPos;
  394.       while (NotDone)
  395.       {
  396.          if (*CurPos == ' ' || *CurPos == '\t')
  397.          {
  398.             *CurPos = '\0';
  399.             while (*(++CurPos) == ' ' || *CurPos == '\t');
  400.             TerminationChar = ' ';
  401.             NotDone = FALSE;
  402.          }
  403.          switch(c = *CurPos)
  404.          {
  405.             case '\0':
  406.                c = *CurPos = '\n';
  407.             case '-':
  408.             case ',':
  409.             case ':':
  410.             case '\n':
  411.                TerminationChar = c;
  412.                *CurPos++ = '\0';
  413.                NotDone = FALSE;
  414.                break;
  415.  
  416.             default:
  417.                if (NotDone)
  418.                {
  419.                   if (NOTPRINTABLE(c) || (CurPos != CurWord && NOTALPHANUM(c)))
  420.                   {
  421.                      TerminationChar = c;
  422.                      NotDone = FALSE;
  423.                   }
  424.                   CurPos++;
  425.                }
  426.                break;
  427.          }
  428.       }
  429.    }
  430. }
  431.  
  432.  
  433. /*
  434.  *  FindWord()
  435.  *
  436.  *  Search the KeyWord array (containing Count entries) for an entry with
  437.  *  Name equal to theWord.  Return the corresponding Code value, or BADVALUE
  438.  *  if theWord does not appear in the KeyWord array.
  439.  *
  440.  *  KeyWord[] must be sorted by name, since we use a binary search to find
  441.  *  theWord witin it.
  442.  */
  443.  
  444. static int FindWord(theWord,KeyWord,Count)
  445. char *theWord;
  446. struct Definition KeyWord[];
  447. int Count;
  448. {
  449.    int value = BADVALUE;
  450.    register short Min,Max, Num;
  451.    register int comp;
  452.    
  453.    Max = Count; Min = -1;
  454.    while ((Num = (Min + Max) >> 1) != Min && value == BADVALUE)
  455.    {
  456.       comp = stricmp(theWord,KeyWord[Num].Name);
  457.       if (comp < 0) Max = Num; else if (comp > 0) Min = Num;
  458.          else value = KeyWord[Num].Code;
  459.    }
  460.    return(value);
  461. }
  462.  
  463.  
  464. /*
  465.  *  FindQualifier()
  466.  *
  467.  *  Find a qualifier name in the Qualifier[] array.
  468.  */
  469. #define FindQualifier(w)    FindWord(w,Qualifier,MAXQUALIFIER)
  470.  
  471.  
  472. /*
  473.  *  FindKeyCode()
  474.  *
  475.  *  Find the scan-code for the given key name.  If the key name is a single
  476.  *  ASCII character, use the AsciiToKeyCode array to look up the scan-code
  477.  *  directly, otherwise use FindWord() to search the Key[] array.
  478.  */
  479.  
  480. static int FindKeyCode(theWord)
  481. char *theWord;
  482. {
  483.    int value = BADVALUE;
  484.    
  485.    if (strlen(theWord) == 1)
  486.    {
  487.       if (PRINTABLE(*theWord)) value = AsciiToKeyCode[*theWord-'!'];
  488.    } else {
  489.       value = FindWord(theWord,Key,MAXKEY);
  490.    }
  491.    return(value);
  492. }
  493.  
  494.  
  495. /*
  496.  *  GetKeyCode()
  497.  *
  498.  *  Parse a set of qualifiers and a key name and return the KeyCode longword
  499.  *  that describes the designated key.  SHIFT, AMIGA, and ALT flags are 
  500.  *  used to indicate when more than one key is designated.  Return BADVALUE
  501.  *  if there is an error parsing the line.
  502.  *
  503.  *  Get the next word on the line, and check the termination character.  
  504.  *  Qualifiers end with dashes, commas, or spaces; key-names end with a colon.
  505.  *  Try to find the qualifier or key-name in the proper list, and give an error
  506.  *  if it can not be found, or if the name is null.  For a qualifier, set its
  507.  *  flag bit in the KeyCode longword.  For key-names, set the scan-code and
  508.  *  the set the SHIFT bit in the qualifier flag bits if necessary.
  509.  *  If the end of the line is reached, display an error.  If some other
  510.  *  delimiter was found, then display an error (making unprintable characters
  511.  *  printable).
  512.  *
  513.  *  Once a key-name is found, stop looking for more words.
  514.  */
  515.  
  516. static void GetKeyCode(theKey)
  517. long *theKey;
  518. {
  519.    short NotDone = TRUE;
  520.    int value;
  521.  
  522.    *theKey = 0;
  523.    while (NotDone)
  524.    {
  525.       GetNextWord();
  526.       switch(TerminationChar)
  527.       {
  528.          case '-':
  529.          case ',':
  530.          case ' ':
  531.             if (strlen(CurWord))
  532.             {
  533.                value = FindQualifier(CurWord);
  534.                if (value > BADVALUE)
  535.                   *theKey |= (1 << value);
  536.                  else
  537.                   *theKey = Error("Unrecognized key qualifier '%s'",CurWord);
  538.             } else {
  539.                *theKey = Error("Missing qualifier keyword");
  540.             }
  541.             break;
  542.  
  543.          case ':':
  544.             if (strlen(CurWord))
  545.             {
  546.                value = FindKeyCode(CurWord);
  547.                if (value > BADVALUE)
  548.                {
  549.                   *theKey |= ((value & (~SHIFT)) << 24) |
  550.                              ((value & SHIFT) << 9);
  551.                } else {
  552.                   *theKey = Error("Unrecognized key name '%s'",CurWord);
  553.                }
  554.             } else {
  555.                *theKey = Error("Key name not specified");
  556.             }
  557.             NotDone = FALSE;
  558.             break;
  559.  
  560.          case '\n':
  561.             *theKey = Error("Key name ends prematurely");
  562.             NotDone = FALSE;
  563.             break;
  564.  
  565.          default:
  566.             if ((TerminationChar & 0x7F) >= ' ')
  567.                *theKey = Error("Illegal delimiter character '%c'",
  568.                   (char)TerminationChar);
  569.               else
  570.                *theKey = Error("Illegal delimiter character '^%c'",
  571.                   (char)((TerminationChar & 0x7F) + '@'));
  572.             break;
  573.       }
  574.    }
  575. }
  576.  
  577.  
  578. /*
  579.  *  GetKeyAction()
  580.  *
  581.  *  Parse the rest of the input line for a key-action keyword.  First, remove
  582.  *  leading and training blanks, and replace the final new-line with a NULL.
  583.  *  Look up the remainder of the line (if any) in the Action[] array, and
  584.  *  if it is not found, report the error.
  585.  */
  586.  
  587. static void GetKeyAction(theAction)
  588. short *theAction;
  589. {
  590.    *theAction = BADVALUE;
  591.  
  592.    while (*CurPos == ' ' || *CurPos == '\t') CurPos++;
  593.    CurWord = CurPos;
  594.    CurPos = CurPos + strlen(CurWord) - 1;
  595.    if (*CurPos == '\n') *CurPos-- = '\0';
  596.    while (*CurPos == ' ' || *CurPos == '\t') *CurPos-- = '\0';
  597.  
  598.    if (*CurWord)
  599.    {
  600.       *theAction = FindWord(CurWord,Action,MAXACTION);
  601.       if (*theAction == BADVALUE) Error("Unrecognized action '%s'",CurWord);
  602.    } else {
  603.       Error("No action specified");
  604.    }
  605. }
  606.  
  607.  
  608. /*
  609.  *  KeyCompare()
  610.  *
  611.  *  Return a positive number if the first key is bigger than the second,
  612.  *  zero if they are equal, and a negative number if the second key is 
  613.  *  bigger.  This routine is used by mSort() to sort the keys.
  614.  */
  615.  
  616. static int KeyCompare(key1,key2)
  617. struct HotKeyItem *key1, *key2;
  618. {
  619.    return(key1->hki_KeyCode - key2->hki_KeyCode);
  620. }
  621.  
  622.  
  623. /*
  624.  *
  625.  *  KeyDispose()
  626.  *
  627.  *  Remove a duplicate key definition and report the fact that a key is
  628.  *  multiply defined (it takes a little work to get the qualifier and key
  629.  *  names back out of the arrays).  This routine is called by mSort() when
  630.  *  it finds duplicate keys.
  631.  */
  632.  
  633. static void KeyDispose(key)
  634. struct HotKeyItem *key;
  635. {
  636.    short i;
  637.    UBYTE code = key->hki_Code & 0x7F;
  638.    int KeyNotFound = TRUE;
  639.    long mask = 0xFFFFFFFF;
  640.  
  641.    printf("Key ");
  642.    for (i=0; i<MAXQUALIFIER; i++)
  643.       if (key->hki_KeyCode & (1 << Qualifier[i].Code) & mask)
  644.       {
  645.          printf("%s-",Qualifier[i].Name);
  646.          mask &= ~(1 << Qualifier[i].Code);
  647.       }
  648.    for (i=0; i<MAXKEY && KeyNotFound; i++)
  649.       if (code == Key[i].Code)
  650.       {
  651.          printf("%s",Key[i].Name);
  652.          KeyNotFound = FALSE;
  653.       }
  654.    for (i=0; i<MAXASCII && KeyNotFound; i++)
  655.    {
  656.       if (code == AsciiToKeyCode[i])
  657.       {
  658.          printf("%c",i+'!');
  659.          KeyNotFound = FALSE;
  660.       }
  661.    }
  662.    printf(" multiply defined\n");
  663.    KeyCount--;
  664.    key->Next = key->Prev = NULL;
  665.    FreeMem(key,sizeof(*key));
  666. }
  667.  
  668.  
  669. /*
  670.  *  GetKeyList()
  671.  *
  672.  *  Read each line from the file (incrementing the line count as we go), 
  673.  *  and skip leading spaces and blank lines.  Get the key code and key action
  674.  *  specified on the line.  If no error was found, add the key definition 
  675.  *  to the linked list of keys defined.  If SHIFT, AMIGA, or ALT were specified,
  676.  *  then add one key each for the left and right version of that qualifier.
  677.  */
  678.  
  679. static void GetKeyList()
  680. {
  681.    long theKey;
  682.    short theAction;
  683.    struct HotKeyItem *TempKey;
  684.    UWORD mask,multikeys;
  685.    extern char *fgets();
  686.  
  687.    while (feof(InFile) == FALSE)
  688.    {
  689.       CurPos = fgets(InputLine,LINESIZE,InFile);
  690.       TerminationChar = '\0';
  691.       LineCount++;
  692.       while (*CurPos == ' ' || *CurPos == '\t') CurPos++;
  693.  
  694.       if (CurPos != NULL && *CurPos != '\0' && *CurPos != '\n')
  695.       {
  696.          GetKeyCode(&theKey);
  697.          GetKeyAction(&theAction);
  698.          if (theKey != BADVALUE && theAction != BADVALUE)
  699.          {
  700.             multikeys = (theKey >> 15) & 0xFE;
  701.             multikeys |= multikeys << 1;
  702.             if (multikeys == 0) multikeys = 1;
  703.             for (mask=1; multikeys; mask<<=1,multikeys>>=1)
  704.             {
  705.                if (multikeys & 1)
  706.                {
  707.                   NEW(HotKeyItem,TempKey);
  708.                   TempKey->hki_KeyCode = theKey;
  709.                   TempKey->hki_Flags   = 0;
  710.                   TempKey->hki_Qual   |= mask >> 1;
  711.                   TempKey->hki_KeyMask = 0xFFFFFFFF;
  712.                   TempKey->hki_Action  = theAction;
  713.                   TempKey->Next = KeyList;
  714.                   KeyList = TempKey;
  715.                   KeyCount++;
  716.                }
  717.             }
  718.          }
  719.       }
  720.    }
  721. }
  722.  
  723.  
  724. /*
  725.  *  SetKeyMasks()
  726.  *
  727.  *  For each key scan-code, we OR together the qualifier masks for all the
  728.  *  definitions for that scan-code and set the key Mask value for each
  729.  *  key with that scan-code to the final ORed mask.  That is, the Mask value
  730.  *  indicates what qualifiers are important for determining when a key has
  731.  *  been pressed (and distinguishing it from other definitions using the
  732.  *  same scan-code but different qualifiers).
  733.  */
  734.  
  735. static void SetKeyMasks()
  736. {
  737.    struct HotKeyItem *CurKey = KeyList;
  738.    struct HotKeyItem *LastKey = CurKey;
  739.    UWORD Mask;
  740.  
  741.    while (LastKey)
  742.    {
  743.       Mask = 0;
  744.       while (CurKey && CurKey->hki_Code == LastKey->hki_Code)
  745.       {
  746.          Mask |= CurKey->hki_Qual;
  747.          CurKey = CurKey->Next;
  748.       }
  749.       if (Mask == 0) Mask = KEYMASK;
  750.       do
  751.       {
  752.          LastKey->hki_Mask = Mask;
  753.          LastKey = LastKey->Next;
  754.       } while (LastKey != CurKey);
  755.    }
  756. }
  757.  
  758.  
  759. /*
  760.  *  MakeKeyArray()
  761.  *
  762.  *  If there are any keys defined, allocate enough space for the KeyArray
  763.  *  that will contain the key definitions, then go through the list and
  764.  *  copy the definitions into the array.  Free each item from the list once it
  765.  *  is copied.  The array saves space (it does not need to contain pointers 
  766.  *  to next and previous items), and allows for easy implementation of a 
  767.  *  binary search on the array.
  768.  */
  769.  
  770. static void MakeKeyArray()
  771. {
  772.    struct HotKeyItem *TempKey;
  773.    short i;
  774.  
  775.    if (KeyCount)
  776.    {
  777.       KeyArray = (struct HotKey *)New("KeyArray",KEYARRAYSIZE);
  778.       for (i=0; i<KeyCount; i++)
  779.       {
  780.          KeyArray[i].hk_KeyCode = KeyList->hki_KeyCode;
  781.          KeyArray[i].hk_KeyMask = KeyList->hki_KeyMask;
  782.          TempKey = KeyList; KeyList = KeyList->Next;
  783.          FreeMem(TempKey,sizeof(*TempKey));
  784.       }
  785.    }
  786. }
  787. #endif
  788.  
  789.  
  790. /*
  791.  *  MakeDefaultArray()
  792.  *
  793.  *  Copy the DefaultKey[] array into a dynamically allocated array that can
  794.  *  be passed to the input handler and still remain in memory even when the
  795.  *  original process is unloaded.
  796.  */
  797.  
  798. static void MakeDefaultArray()
  799. {
  800.    short i;
  801.    
  802.    KeyCount = DEFAULTSIZE;
  803.    KeyArray = (struct HotKey *)New("KeyArray",KEYARRAYSIZE);
  804.    for (i=0; i<KeyCount; i++)
  805.    {
  806.       KeyArray[i].hk_KeyCode = DefaultKey[i].hk_KeyCode;
  807.       KeyArray[i].hk_KeyMask = DefaultKey[i].hk_KeyMask;
  808.    }
  809. }
  810.  
  811.  
  812. /*
  813.  *  GetKeyArray()
  814.  *
  815.  *  If there is a command-line argument, then 
  816.  *    it must be a file name, so try to open it (error if there is a problem).
  817.  *    Create the key definition list from the lines in the file.
  818.  *    If there were no valid key definitions, 
  819.  *      say so,
  820.  *     otherwise, 
  821.  *      sort the key list,
  822.  *      set the key masks for each scan-code,
  823.  *      make the key array from the sorted list.
  824.  *   otherwise (there was no file name given, so)
  825.  *    make the key array from the default key list.
  826.  */
  827.  
  828. void GetKeyArray(argc,argv)
  829. int argc;
  830. char *argv[];
  831. {
  832. #ifndef NO_FILE
  833.    extern struct HotKeyItem *mSort(); 
  834.  
  835.    if (argc > 1)
  836.    {
  837.       InFile = fopen(argv[1],"r");
  838.       if (InFile == NULL)
  839.          DoExit("Can't Open File '%s':  Error %d",argv[1],ERROR);
  840.       GetKeyList();
  841.       if (KeyCount == 0)
  842.       {
  843.          DoExit("No valid key definitions found in file '%s'",argv[1]);
  844.       } else {
  845.          KeyList = mSort(KeyList,KeyCompare,KeyDispose);
  846.          SetKeyMasks();
  847.          MakeKeyArray();
  848.       }
  849.    } else
  850. #endif
  851.    {
  852.       MakeDefaultArray();
  853.    }
  854. }
  855.